package gbench.sandbox.matlib;

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.stream.Collectors;

import gbench.common.matlib.MatlibCanvas.NVec;
import gbench.common.matlib.MatlibCanvas.XVec;
import gbench.common.matlib.matrix.Matrix;
import gbench.common.matlib.rdd.BasePair;
import gbench.common.matlib.rdd.PVec;
import gbench.common.matlib.matrix.ComplexMatrix;

import static gbench.common.matlib.MatlibCanvas.println;
import static gbench.common.matlib.matrix.Matrix.V;


/**
 * 矩阵对象的使用说明
 * 
 * @author gbench
 *
 */
public class JunitMatrix {

    @Test
    public void foo() {
        final var n = 3;
        final var mx = Matrix.of(n, n, (i, j) -> "a" + (i + 1) + (j + 1));
        println(mx);
        final var c1 = XVec.OF(n, i -> "b" + i);
        final var c2 = XVec.OF(n, i -> "c" + i);
        final var cc = XVec.OF(c1, c2);
        println(mx.mapX(e -> e.zip(c1, BasePair::new)).collect(Matrix.mxclc()));
        println("\n", mx);
        println("\n", mx.flatMapX(e -> cc.map(c -> e.zip(c))).stream().collect(Matrix.mxclc(true)));
        println("\n", mx.mapX(r -> cc.fmap(c -> r.zip(c))).collect(Matrix.mxclc()));
    }

    @Test
    public void bar() {
        final var aa = Matrix.of(2, 2, XVec.OF("a11 A21 A21^T A22".split(" ")));
        final var vv = XVec.OF("-1/a11*A21^T*X X".split(" "));
        final var v2 = XVec.OF("-1/a11*A21^T*X X^T".split(" "));
        final var dd = aa.mapX(p -> p.zip(vv).collect(PVec.pvec2clc())).zip(v2);
        dd.foreach(e -> {
            final var a = e._1();
            final var b = e._2();
            final var x = a.mapX(p -> p.append(b).flattenS(w -> (String) w)
                .flatMap(line -> Arrays.stream(line.split("\\*")))
                .sorted()
                .collect(Collectors.toList()));
            println(x);
        });
    }

    /**
     * 矩阵乘法
     */
    @Test
    public void qux() {
        final var n = 4;
        final var aa = Matrix.of(n, n, NVec.of(16, i -> i)); // 左矩阵
        println("aa:\n", aa);
        final var cc = XVec.OF(2,i->NVec.of(n, j -> (i+1)*j)); // 右矩阵
        println("\ncc:\n",cc.collect(Matrix.mxclc(true)));
        println("\naa %*% cc \n", aa.mapX(r -> cc.fmap(c -> r.zipU(c, (a, b) -> a * b, NVec.nveclc()).sum())).collect(Matrix.mxclc()));
    }
    
    /**
     * 数据行的切分排序
     */
    @Test
    public void split() {
        final var mx = NVec.of(100, i -> i).collect(Matrix.mxclc(10, 10, false)); // 制作一个数据矩阵
        final var r = mx.row(1); // 提取索引号1行数据
        println(r);// 打印数据
        println(r.sorted2((i, p) -> i.equals(5) ? -1 : 1)); // 把 所谓位置5的元素排在首位
        println(r.splitX(NVec.of(5, 2).accum2())); // 切分为长度 5,2,(r.size()-5-2)的长度序列
    }
    
    @Test
    public void mmult() {
        final var left = NVec.of(100, i -> i).collect(Matrix.mxclc(10, 10, false));
        final var ret = Matrix.mmultf(V(10, i -> 1d)).apply(left);

        println(left);
        println("-----------------------------------------------");
        println(ret);

        final var aa = NVec.of(10, i -> 1d);
        final var bb = aa.stridesN().insert(0, 1d);

        println(bb.rev().accum());
    }
    
    @Test
    public void mmult2() {
        final var n = 5; // 数据维度
        final var left = NVec.of(n * n, i -> i).collect(ComplexMatrix.mxclc(n, n, false));
        final var right = NVec.of(n, i -> 1).collect(ComplexMatrix.mxclc(n, 1));
        println(left);
        println("------------------------------");
        println(right.transpose());
        println("------------------------------");
        println(left.mmult(right).transpose());
        println("------------------------------");
        println(right.mmult(NVec.of(n, i -> i)));
        println("------------------------------");
        final var a = NVec.of(n, i -> i).collect(ComplexMatrix.mxclc(n, 1));
        final var b = NVec.of(n, i -> i).collect(ComplexMatrix.mxclc(1, n));
        println(a.mmult(b));
    }
}
